#pragma once

#include <signal.h>
#include <fcntl.h>
#include "TcpServer.hpp"
#include "ThreadPool.hpp"
#include "Channel.hpp"
#include "TcpConnection.hpp"
#include <execinfo.h>

const int PORT = 8080;
const int THREAD_NUM = 5;

void debug(int signo)
{
    fprintf(stderr, "catch Segmentation fault!!!\n");
#define SIZE 100
    FILE *fh;
    if (!(fh = fopen("../http/dbg_msg.log", "w+")))
        exit(0);
    void *buffer[100];
    int nptrs;
    nptrs = backtrace(buffer, SIZE);
    backtrace_symbols_fd(buffer, nptrs, fileno(fh));
    fflush(fh);
    exit(-1);
}

class HttpServer
{
public:
    HttpServer(int port = PORT)
        : _port(port)
    {
    }
    ~HttpServer()
    {
        if (_lfd > 0)
            close(_lfd);
    }
    void InitServer()
    {
        // 忽略SIGPIPE信号
        signal(SIGPIPE, SIG_IGN);
        signal(SIGSEGV, &debug);
        TcpServer *tsvr = TcpServer::GetInstance(_port);
        // 获取监听描述符
        _lfd = tsvr->GetListenSock();
        LOG(INFO) << "listen fd: " << _lfd << "\n";
        // 创建事件模型
        _mainLoop = new EventLoop;
        // 创建线程池
        _tp = new ThreadPool(THREAD_NUM, _mainLoop);
    }
    void Run()
    {
        // 启动线程池  创建好子线程
        _tp->Run();
        // 添加检测任务
        // LOG(INFO) << "listen fd: " << _lfd << "\n";
        Channel *channel = new Channel(_lfd, ReadEvent, AcceptConnection, nullptr, this);
        _mainLoop->addTask(channel, ADD);
        // 启动反应堆模型 主线程检测监听描述符是否被激活
        _mainLoop->run();
    }

private:
    static int AcceptConnection(void *arg)
    {
        HttpServer *httpserver = (HttpServer *)arg;
        //  获取新连接并放入epoll模型中
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        int newfd = accept(httpserver->_lfd, (sockaddr *)&peer, &len);
        if (newfd < 0)
        {
            LOG(WARNING) << "accept newfd fail\n";
            return -1;
        }
        LOG(INFO) << newfd << std::endl;
        // 将新连接设置为非阻塞并添加到epoll模型中
        httpserver->SetNoBlock(newfd);
        // 将事件添加到子线程的事件模型中
        EventLoop *evLoop = httpserver->_tp->GetEventLoop();
        LOG(INFO) << evLoop->_threadName << std::endl;
        // 将新连接放到TcpConnection中处理
        TcpConnection *tcpConnection = new TcpConnection(newfd, evLoop);
        tcpConnection->Run();
        return 0;
    }
    void SetNoBlock(int fd)
    {
        // 获取状态标记
        int flag = fcntl(fd, F_GETFL);
        if (flag < 0)
        {
            LOG(WARNING) << "fcntl fail: F_GETFL\n";
            return;
        }
        // 设置
        fcntl(fd, F_SETFL, flag | O_NONBLOCK);
    }

private:
    int _port;
    int _lfd;
    EventLoop *_mainLoop;
    ThreadPool *_tp;
};